#include "nftables.h"
#include <iostream>

void Nftables::install()
{
    system("echo \"\n[INSTALL NFTABLES]\" && sleep 1");
    system("pacman -S nftables --noconfirm");
}
void Nftables::print_ruleset()
{
    system("nft list ruleset");
}
void Nftables::save_ruleset()
{
    system("nft list ruleset > /etc/nftables.conf"); // Auto-start rules nftables
}
void Nftables::flush_ruleset()
{
    system("echo \"\n[FLUSH RULESET NFTABLES]\" && sleep 1");
    system("nft flush ruleset"); 
}
void Nftables::enableLogging()
{
    system("echo \"net.netfilter.nf_log.2 = nfnetlink_log\" > /etc/sysctl.conf"); // change level logging (uncomment it if you want logging)
}


// ? ipV4
void Nftables::add_filter_table_ip_v4()
{
    system("nft add table ip filter"); // Create table filter    
    system("nft add chain ip filter INPUT { type filter hook input priority 0 \\; policy drop \\;}");     // Add chain INPUT
    system("nft add chain ip filter FORWARD { type filter hook forward priority 0 \\; policy drop \\;}"); // Add chain FORWARD
    system("nft add chain ip filter OUTPUT { type filter hook output priority 0 \\; policy drop \\;}");   // Add chain OUTPUT
}
void Nftables::add_input_rules_in_filter_table_to_ip_v4_to_accept()
{
    system("nft add rule ip filter INPUT iif \"lo\" counter log prefix \"Loopback\" accept");                                                                                  // Allow loopback
    system(("nft add rule ip filter INPUT iif " + interface + " tcp sport {80, 443} ct state related, established counter log prefix \\\"[IN HTTP/HTTPS]\\\" accept").data()); // Allow HTTP, HTTPS
    system(("nft add rule ip filter INPUT iif " + interface + " udp sport 53 ct state related, established counter log prefix \\\"[IN DNS]\\\" accept").data());               // Allow DNS
    system(("nft add rule ip filter INPUT iif " + interface + " udp sport {67, 68} ct state related, established counter log prefix \\\"[IN DHCP]\\\" accept").data());        // Allow DHCP
    system(("nft add rule ip filter INPUT iif " + interface + " ip protocol icmp ct state related, established counter log prefix \\\"[IN ICPM]\\\" accept").data());          // Allow ICPM (ping my pc) 
    system(("nft add rule ip filter INPUT iif " + interface + " meta pkttype { broadcast, multicast } drop ").data());                                                         // DROP broadcast, multicast pkgs
    system(("nft add rule ip filter INPUT iif " + interface + " ct state invalid drop").data());                                                                               // DROP invalid pkg
    system(("nft add rule ip filter INPUT iif " + interface + " icmp type echo-reply drop").data());                                                                           // Drop pkg ICMP type  0 (Echo Reply)
    system(("nft add rule ip filter INPUT iif " + interface + " icmp type echo-request drop").data());                                                                         // Drop pkg ICMP type 8 (Echo Request)
    system("nft add rule ip filter INPUT counter drop");   
}
void Nftables::add_forward_rules_in_filter_table_to_ip_v4_to_drop()
{
    system("nft add rule ip filter FORWARD counter drop");
}
void Nftables::add_output_rules_in_filter_table_to_ip_v4_to_accept()
{
    system("nft add rule ip filter OUTPUT oif \"lo\" ip protocol icmp counter accept");                                                             // Allow ICPM (ping my pc)
    system(("nft add rule ip filter OUTPUT oif " + interface + " tcp dport {80, 443} counter log prefix \\\"[OUT HTTP, HTTPS]\\\" accept").data()); // Allow HTTP, HTTPS
    system(("nft add rule ip filter OUTPUT oif " + interface + " udp dport 53 counter log prefix \\\"[OUT DNS]\\\" accept").data());                // Allow DNS
    system(("nft add rule ip filter OUTPUT oif " + interface + " ip protocol icmp counter log prefix \\\"[OUT ICPM]\\\" accept").data());           // Allow ICPM (ping other pc) 
    system(("nft add rule ip filter OUTPUT oif " + interface + " udp dport {67, 68} counter log prefix \\\"[OUT DHCP]\\\" accept").data());         // Allow DHCP
    system(("nft add rule ip filter OUTPUT oif " + interface + " meta pkttype { broadcast, multicast } drop").data());                              // DROP broadcast, multicast pkgs
    system(("nft add rule ip filter OUTPUT oif " + interface + " ct state invalid drop").data());                                                   // DROP invalid pkgs
    system("nft add rule ip filter OUTPUT counter drop");                                                                                           // DROP other
}

void Nftables::add_input_rules_in_filter_table_to_ip_v4_to_drop()
{
    system("nft add rule ip filter INPUT iif \"lo\" counter log prefix \"Loopback\" accept");                                                                                  // Allow loopback
    system(("nft add rule ip filter INPUT iif " + interface + " meta pkttype { broadcast, multicast } drop ").data());                                                         // DROP broadcast, multicast pkgs
    system(("nft add rule ip filter INPUT iif " + interface + " ct state invalid drop").data());                                                                               // DROP invalid pkg
    system(("nft add rule ip filter INPUT iif " + interface + " icmp type echo-reply drop").data());                                                                           // Drop pkg ICMP type  0 (Echo Reply)
    system(("nft add rule ip filter INPUT iif " + interface + " icmp type echo-request drop").data());                                                                         // Drop pkg ICMP type 8 (Echo Request)
    system("nft add rule ip filter INPUT counter drop");   
}
void Nftables::add_output_rules_in_filter_table_to_ip_v4_to_drop()
{
    system("nft add rule ip filter OUTPUT oif \"lo\" ip protocol icmp counter accept");                                                             // Allow ICPM (ping my pc)
    system(("nft add rule ip filter OUTPUT oif " + interface + " meta pkttype { broadcast, multicast } drop").data());                              // DROP broadcast, multicast pkgs
    system(("nft add rule ip filter OUTPUT oif " + interface + " ct state invalid drop").data());                                                   // DROP invalid pkgs
    system("nft add rule ip filter OUTPUT counter drop");                                                                                           // DROP other
}

// ? ipV6
void Nftables::add_filter_table_ip_v6() {
    system("nft add table ip6 filter");
    system("nft add chain ip6 filter INPUT { type filter hook input priority 0 \\; policy drop \\;}");
    system("nft add chain ip6 filter FORWARD { type filter hook forward priority 0 \\; policy drop \\;}");
    system("nft add chain ip6 filter OUTPUT { type filter hook output priority 0 \\; policy drop \\;}");
}
void Nftables::add_input_rules_in_filter_table_to_ip_v6_to_drop()
{
    system("nft add rule ip6 filter INPUT counter log prefix \\\"[IN IPV6]\\\" drop"); 
}
void Nftables::add_forward_rules_in_filter_table_to_ip_v6_to_drop()
{
    system("nft add rule ip6 filter FORWARD counter drop");
}
void Nftables::add_output_rules_in_filter_table_to_ip_v6_to_drop() {
    system("nft add rule ip6 filter OUTPUT counter drop");
}

void Nftables::setInteface(std::string interface)
{
    if (interface != "") this->interface = interface;
}

std::string Nftables::getInteface()
{
    return this->interface;
}
